//
//  ViewController.m
//  RACDemo
//
//  Created by XFB on 2018/8/4.
//  Copyright © 2018年 ZhouCheng. All rights reserved.
//

#import "ViewController.h"
#import "ReactiveObjC.h"
#import "CustomView.h"
#import "Member.h"
#import "ListViewController.h"

#import "RACReturnSignal.h"


@interface ViewController () <Page2Delegate>

@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (nonatomic, assign) int age;

@end

@implementation ViewController

/**
 
 信号 -> 订阅 (响应式编程思想，只要信号一变化，马上通知你)
 RACSignal: 信号， ReactiveCocoa最基本类
 RACDisposable: 处理数据，清空数据
 block: 什么时候执行，block能干嘛
 
 RACSubscriber: 订阅者，发送信号消息
 信号本身不具备发送消息能力
 
 先订阅 再发送消息
 
 在订阅就会执行RACSignal的block

 */
- (void)viewDidLoad {
    [super viewDidLoad];

//    [self test1];
    /// 先订阅再发送消息
//    [self test2];
    /// 先发送消息再订阅
//    [self test3];
    /// 代理的设置
//    [self test4];
    /// 集合
//    [self test5];
    /// 网络请求
//    [self test6];
    /// RACCommand: 处理事件
//    [self test7];
    /// 登录按钮事件
//    [self test8];
    /// 监听方法
//    [self test9];
    /// 绑定数据
//    [self test10];
    /// 发送通知
//    [self test11];
    /// 按钮的响应
//    [self test12];
    /// KVO
//    [self test13];
    /// bind数据
//    [self test14];
}

- (void)test14
{
    /// 需求:每次在文本框后面加上 ZC
    [[_textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
       
        return ^RACSignal *(id value, BOOL *stop) {
            /// 信号一改变，就会执行，并且把值传递过来
            NSLog(@"信号block %@", value);
            NSString *result = [NSString stringWithFormat:@"%@%@", value, @"ZC"];
            return [RACReturnSignal return:result];
        };
        /// RACSubscriber: next
        /// RACSubscriber sendNext
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"获取到处理完的数据%@", x);
        self.label.text = [NSString stringWithFormat:@"%@", x];
    }];
}

/// 此方法会在使用Segue的时候自动调用
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    /// 将page2变量设置为segue所跳转的界面控制器
    id page2 = segue.destinationViewController;
    /// 对page2中的白能量设置值
    [page2 setValue:self.textField.text forKey:@"string"];
    
    /// 设置委托代理
    [page2 setValue:self forKey:@"delegate"];
}

/// 实现代理 反向传值
- (void)passValue:(NSString *)value
{
    self.textField.text = value;
}

- (void)test13
{
    /// KVO
//    [self rac_valuesForKeyPath:nil observer:nil];
//    [self rac_valuesAndChangesForKeyPath:nil options:nil observer:nil];
//    [[self rac_valuesForKeyPath:@keypath(self, age) observer:self] subscribeNext:^(id  _Nullable x) {
//        NSLog(@"%@", x);
//    }];
    
    /// 整合后的KVO
    /**
     注意: KVO宏 @"age" 直接写属性名，不要包装成字符串
     */
    [RACObserve(self, age) subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.age ++;
}

- (void)test12
{
    /// RAC监听: subscribeNext 方法订阅信号
    [[_loginButton rac_signalForControlEvents:UIControlEventTouchDown] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"%@", x);
    }];
}

- (void)test11
{
    /// 监听通知
    /// 管理观察者: 不需要管理观察者,RAC内部管理
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"note" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        NSLog(@"监听到通知%@",x);
    }];
    /// 发出通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil];
}


- (void)test10
{
    /// 方式1
//    [_textField addTarget:self action:@selector(textDidChange) forControlEvents:UIControlEventEditingChanged];
//    [_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
//        NSLog(@"%@", x);
//        self->_label.text = x;
//    }];
    
    /// 方式2
    /// 绑定 666
    RAC(_label, text) = _textField.rac_textSignal;

}

//- (void)textDidChange
//{
//    NSLog(@"%@", _textField.text);
//}

- (void)test9
{
    /// 创建请求最热数据信号
    RACSignal *hotSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        /// 请求最热信号
        [subscriber sendNext:@"最热数据"];
        return nil;
    }];
    
    /// 创建请求最新数据信号
    RACSignal *newSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        /// 请求最新的数据
        [subscriber sendNext:@"最新数据"];
        return nil;
    }];
    
    /// Selector: 当数组所有信号都发送next
    /// rac_liftSelector硬件要求: 有几个信号就必须有几个参数,参数就是信号发出的值
    [self rac_liftSelector:@selector(updateUIWithHot:new:) withSignalsFromArray:@[hotSignal, newSignal]];
}

- (void)updateUIWithHot:(NSString *)hot new:(NSString *)new
{
    NSLog(@"更新UI %@ %@",hot, new);
}

- (void)test8
{
    /**
     RACCommand基本使用:
     RACCommand原理:
     
     RACCommand:
     监听按钮点击,网络请求
     */
//    _loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
//
//        /// commadBlock
//        NSLog(@"点击了按钮%@", input);
//
//        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
//            /// 信号block
//            [subscriber sendNext:input];
//            return nil;
//        }];
//    }];
    
    RACSubject *enableSignal = [RACSubject subject];
    
    _loginButton.rac_command = [[RACCommand alloc] initWithEnabled:enableSignal signalBlock:^RACSignal * _Nonnull(id  _Nullable input) {

        /// commandBlock
        NSLog(@"点击了按钮%@", input);

        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            /// 信号Block
            [subscriber sendNext:input];
            /// 请求完成的时候调用
            [subscriber sendCompleted];
            return nil;
        }];
    }];
    
    [[_loginButton.rac_command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
        BOOL executing = [x boolValue];
        [enableSignal sendNext:@(!executing)];
    }];
    
    /// 监听
    [_loginButton.rac_command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
}

- (void)test7
{
    /// 创建RACCammand
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
       
        NSLog(@"执行Block%@", input);
        
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            

            /// 信号的block
            NSLog(@"执行信号的block");
            
            /// 发送数据 -> RACReplaySubject
            [subscriber sendNext:@"你好!"];
            
            /// 发送完成
            [subscriber sendCompleted];
            
            return  nil;
        }];
    }];

    
    /// 订阅command信号
    /// executionSignals: 信号中信号，信号发送信号
    /// switchToLatest: 获取最新发送的信号
    [command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    /// 监听命令的执行情况,有没有完成
    [[command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
        BOOL isExecuting = [x boolValue];
        if (isExecuting) {
            NSLog(@"正在执行");
        } else {
            NSLog(@"执行完成");
        }
    }];

    /*
    [command.executing subscribeNext:^(NSNumber * _Nullable x) {
        
        BOOL isExecuting = [x boolValue];
        
        if (isExecuting) {
            NSLog(@"正在执行");
        } else {
            NSLog(@"执行完成");
        }
    }];
    
    [command.executionSignals subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
        
        [x subscribeNext:^(id  _Nullable x) {
            NSLog(@"%@", x);
        }];
    }];
    */
    
    /// 执行execute 就会执行
    RACReplaySubject *subject = [command execute:@1];

    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    [[command execute:@1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
}

- (void)test6
{
    @weakify(self)
    
    /**
     创建RACDynamicSignal,保存didSubscribe
     */
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        @strongify(self);
        NSLog(@"网络请求");
    
        [self loadData:^(id data){
            [subscriber sendNext:data];
        }];
        
        return nil;
    }];
    
    /// RACSignal 转换 RACMulticastConnection
    /// RACMulticastConnection: 解决RACSignal副作用
    /// Multicast: 广播连接
    RACMulticastConnection *connention = [signal publish];
    /// 订阅信号: sendNext
    /// RACSubject:RACSubscribe
    [connention.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    [connention.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    /// 进行连接
    /**
     RACSubject订阅signal
     */
    [connention connect];
}

- (void)loadData:(void(^)(id))success
{
    
}

/*
 
 数据优化，开启一个异步线程去处理数据
 RAC集合: 异步线程处理数据
 OC集合: 数组、字典、NSSet
 
 */

- (void)test5
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Member.plist" ofType:nil];
    NSArray *datas = [NSArray arrayWithContentsOfFile:filePath];
    
    NSMutableArray *arrayM = [NSMutableArray array];
    /// 字典转模型
    /// map映射
    /// mapBlock: value参数: 集合      返回值: 需要映射成那个值
//    arrayM = [[datas.rac_sequence map:^id _Nullable(id  _Nullable value) {
//        return [Member initWithDict:value];
//    }] array];

    NSLog(@"%@", arrayM);
    
    /// 转换RAC集合(RACSequence),不能直接更新UI
    [datas.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@", x);
        /// 更新UI
        Member *member = [Member initWithDict:x];
        [arrayM addObject:member];
    } completed:^{
        NSLog(@"%@", arrayM);
        NSLog(@"%@", [NSThread currentThread]);
        /// 不管是用什么框架，一定要记得确认线程，UI界面不显示，可能是线程问题
    }];
}

- (void)test4
{
    CustomView *view = [[CustomView alloc] init];
    view.backgroundColor = [UIColor redColor];
    view.frame = CGRectMake(50, 50, 100, 100);

    RACSubject *subject = [RACSubject subject];
    /// 订阅
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"点击了红色%@", x);
    }];
    
    view.subject = subject;
    
    [self.view addSubview:view];
}


- (void)test2
{
    /// 先订阅 再发送消息
    
    /// 1.创建信号
    RACSubject *subject = [RACSubject subject];
    
    /// 2.订阅 内部创建RACSubcriber，并且保存起来
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"第一个订阅者%@", x);
    }];
    
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"第二个订阅者%@", x);
    }];
    
    /// 3.发送信号 遍历所有的订阅者，执行nextBlock
    [subject sendNext:@1];
}

- (void)test3
{
    /// 注意: 先发送再订阅
    
    /// 1.创建信号
    RACReplaySubject *replaySubject = [RACReplaySubject subject];
    
    /// 2.发送消息
    [replaySubject sendNext:@"123"];
    [replaySubject sendNext:@"321"];
    
    /// 3.订阅信号
    /// 遍历值，让一个订阅者去发送多个值
    /// 只要订阅一次，之前所有发送的值都能获取到
    [replaySubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    /// 总结
    /// 1.多个值一个类可以拿到
    /// 2.一个类想要拿多个值，采用RACReplaySubject
    /// 3.RACReplaySubject价值： 先发送，再订阅
    
}

- (void)test1
{
    /// 创建信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        /// 发送信号变化
        NSLog(@"RACSignal的block");
        /// 网络请求
        [subscriber sendNext:@2];
        [subscriber sendCompleted];
        
        return [RACDisposable disposableWithBlock:^{
            /// 当订阅者被销毁的时候就会执行
            /// 订阅发送完成或者Error，也会执行block
            /// 清空数据
            NSLog(@"RACDisposeable的block");
        }];
    }];
    
    /**
     订阅信号传的值
     底层: 创建订阅者
     注意点: 不要分开订阅，要一起订阅
     */
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"%@", error);
    } completed:^{
        NSLog(@"结束1");
    }];
    
    /// 上面可以分开三个 但是每次会进入上面两个返回 RACSignal的block 和 RACDisposeable的block
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];

    [signal subscribeError:^(NSError * _Nullable error) {
        NSLog(@"%@", error);
    }];

    [signal subscribeCompleted:^{
        NSLog(@"结束2");
    }];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
